home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Camelot
/
Camelot 035 (1989-01)(Swedish User Group of Amiga)(SE)(PD)[m doscopy][WB].zip
/
Camelot 035 (1989-01)(Swedish User Group of Amiga)(SE)(PD)[m doscopy][WB].adf
/
App
/
app.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-01-04
|
9KB
|
409 lines
/* app.c - 68000 assembly pre-processor
*
* written by Karl Lehenbauer (uunet!sugar!karl or karl@sugar.uu.net) 12-8-88
* PUBLIC DOMAIN -- no warranties of usefulness, suitabilitiy, correctness
*
* There're README and make files that go along with this. If you don't
* have them, you've been ripped off.
*/
#include <stdio.h>
#include <assert.h>
#define YES 1
#define NO 0
#define MATCH 0
int current_nest_level = -1;
int master_label_number = 0;
unsigned int line_number = 0;
char *label;
char *opcode;
char *operands;
char *comment;
char *input_filename, *input_extension, *output_filename;
panic(s)
char *s;
{
fprintf(stderr,"app: %s at line %d\n",s,line_number);
fclose(stdout);
unlink(output_filename);
exit(1);
}
/* given a pointer to a line, make the global character pointers "label",
* "opcode", "operands" and "comment" point to the various fields within
* the line, or NULL for any that aren't present. Note that crackline
* butchers the line up by writing null bytes into it.
*/
crackline(s)
register char *s;
{
register char *p = s;
label = NULL;
opcode = NULL;
operands = NULL;
comment = NULL;
/* suck up leading blanks */
while ((*p == ' ') || (*p == '\t'))
p++;
/* if end of line, return -- it's an empty line */
if (*p == '\0')
return;
/* if the first nonblank char is a semicolon, it's a comment */
if (*p == ';')
{
comment = s;
return;
}
/* if the very first char isn't blank (and we already know it's
not a semicolon), it's a label
*/
if ((*s != ' ') && (*s != '\t'))
{
label = s;
p = s + 1;
while (*p != ' ' && *p != '\t' && *p != '\0') p++;
if ((*p == ' ') || (*p == '\t'))
{
*p = '\0';
p++;
}
else
return;
}
else /* there isn't a label, suck up spaces to next parm */
{
p = s;
while ((*p == ' ' || *p == '\t')) p++;
if (*p == '\0')
return;
}
/* if the next parm is a comment, assign and we're done */
if (*p == ';')
{
comment = p;
return;
}
/* we're at the opcode, assign it and terminate with \0 if spaces
* follow, else we're done */
opcode = p;
while (*p != ' ' && *p != '\t' && *p != '\0') p++;
if ((*p == ' ') || (*p == '\t'))
{
*p = '\0';
p++;
}
else
return;
/* if the next parm is a comment, assign and we're done */
if (*p == ';')
{
comment = p;
return;
}
operands = p;
while (*p != ' ' && *p != '\t' && *p != '\0') p++;
if ((*p == ' ') || (*p == '\t'))
{
*p = '\0';
p++;
}
else
return;
comment = p;
}
#ifdef DEBUG
dumpit()
{
printf("label: %s, opcode %s, operands %s, comment %s\n",label,opcode,operands,comment);
}
#endif
char s[255], ssave[255];
#define IF_STATEMENT_TYPE 1
#define ELSE_STATEMENT_TYPE 2
#define DO_STATEMENT_TYPE 3
#define MAX_NESTING_LEVELS 32
struct nesting_context
{
int construct_type;
int label_number;
int second_label_number;
};
struct nesting_context nesting_data[MAX_NESTING_LEVELS];
/* push - push a nesting construct context, executed on .if and .do */
push(new_construct_type,label,second_label)
int new_construct_type, label,second_label;
{
struct nesting_context *np;
if (++current_nest_level >= MAX_NESTING_LEVELS)
panic("too many nesting levels");
np = &nesting_data[current_nest_level];
np->construct_type = new_construct_type;
np->label_number = label;
np->second_label_number = second_label;
}
/* pop - discard the top nesting context, checking for underflow
* called when conditionals have been successfully closed
*/
pop()
{
if (current_nest_level >= 0)
--current_nest_level;
else
panic("'endif' or 'enddo' without a matching 'if' or 'do'");
}
/* generate and return new label number */
newlabel()
{
return(master_label_number++);
}
/* structure in support of reversing the sense of conditionals */
struct condition_code_struct
{
char *condition;
char *reverse_condition;
};
#define N_CONDITION_TYPES 14
struct condition_code_struct condition_code_array[N_CONDITION_TYPES] =
{
{"ne", "eq"},
{"eq", "ne"},
{"lt", "ge"},
{"ge", "lt"},
{"le", "gt"},
{"gt", "le"},
{"cc", "cs"},
{"cs", "cc"},
{"vc", "vs"},
{"vs", "vc"},
{"hi", "ls"},
{"ls", "hi"},
{"pl", "mi"},
{"mi", "pl"},
};
/* given a pointer to text containing a condition code, returns the
* a pointer to text containing a condition with reverse sense of
* the one passed as an argument. Bombs if the sense doesn't make sense
*/
char *reverse_sense_of(s)
char *s;
{
struct condition_code_struct *ccp;
int i;
for (i = 0, ccp = condition_code_array; i < N_CONDITION_TYPES; i++, ccp++)
if (strcmp(s,ccp->condition) == MATCH)
return(ccp->reverse_condition);
panic("invalid condition code in 'if', 'elseif', 'while' or 'until'");
}
/* print the label name corresponding to the number specified, should be
* called in more places in the program where printf is used instead, so
* you have to change it in several places if you want to change what the
* labels look like
*/
print_label(i)
int i;
{
printf("L%d\n",i);
}
/* to prevent parsing every line, looks_promising is a quick hack to see
* if its a line we're interested in or not. If the line doesn't have
* a period as the first non-space or tab char, it's not promising, so
* we don't crack the line with the full blown line parses. This is a
* performance hack.
*/
looks_promising(s)
char *s;
{
while (*s != '\0')
{
if (*s == '.')
return(YES);
if (*s != ' ' && *s != '\t')
return(NO);
s++;
}
return(NO);
}
usage()
{
fprintf(stderr,"usage: app filename.app\n");
exit(1);
}
main(argc,argv)
int argc;
char *argv[];
{
fprintf(stderr,"Hackercorp public domain 68000 assembly preprocessor 0.0 12-9-88\n");
if (argc != 2)
usage();
input_filename = argv[1];
input_extension = input_filename + strlen(input_filename) - 4;
if (strcmp(".app",input_extension) != MATCH)
usage();
if (freopen(input_filename,"r",stdin) == NULL)
{
perror(input_filename);
exit(5);
}
/* kludgily create output filename */
output_filename = input_filename;
strcpy(input_extension,".asm");
if (freopen(input_filename,"w",stdout) == NULL)
{
perror(input_filename);
exit(5);
}
preprocess_file();
}
preprocess_file()
{
struct nesting_context *np;
int i;
/* for all lines in the file */
while (gets(s) != NULL)
{
line_number++; /* count the line */
/* if it's not promising, copy it to output and go on */
if (!looks_promising(s))
{
printf("%s\n",s);
goto more;
}
strcpy(ssave,s);
crackline(s);
if (strcmp(opcode,".if") == MATCH)
{
printf("\tb%s\tL%d\n",reverse_sense_of(operands),i = newlabel());
push(IF_STATEMENT_TYPE,i,-1);
}
else if (strcmp(opcode,".else") == MATCH)
{
np = &nesting_data[current_nest_level];
if (np->construct_type != IF_STATEMENT_TYPE)
panic("'else' without 'if'");
printf("\tbra\tL%d\n",i = newlabel());
/* print the label from the top context */
print_label(np->label_number);
np->label_number = i;
np->construct_type = ELSE_STATEMENT_TYPE;
}
else if (strcmp(opcode,".endif") == MATCH)
{
np = &nesting_data[current_nest_level];
if ((np->construct_type != IF_STATEMENT_TYPE)
&& (np->construct_type != ELSE_STATEMENT_TYPE))
panic("'endif' without 'if' or 'else'");
print_label(np->label_number);
pop();
}
else if (strcmp(opcode,".elseif") == MATCH)
{
np = &nesting_data[current_nest_level];
if (np->construct_type != IF_STATEMENT_TYPE)
panic("'else' without 'if'");
printf("\tbra\tL%d\n",i = newlabel());
/* print the label from the top context */
print_label(np->label_number);
np->label_number = i;
printf("\tb%s\tL%d\n",reverse_sense_of(operands),i);
}
else if (strcmp(opcode,".do") == MATCH)
{
print_label(i = newlabel());
push(DO_STATEMENT_TYPE,i,newlabel());
}
else if (strcmp(opcode,".while") == MATCH)
{
np = &nesting_data[current_nest_level];
if (np->construct_type != DO_STATEMENT_TYPE)
panic("'while' without 'do'");
printf("\tb%s\tL%d\n",reverse_sense_of(operands),np->second_label_number);
}
else if (strcmp(opcode,".enddo") == MATCH)
{
np = &nesting_data[current_nest_level];
if (np->construct_type != DO_STATEMENT_TYPE)
panic("'enddo' without 'do'");
printf("\tbra\tL%d\n",np->label_number);
print_label(np->second_label_number);
pop();
}
else if (strcmp(opcode,".until") == MATCH)
{
np = &nesting_data[current_nest_level];
if (np->construct_type != DO_STATEMENT_TYPE)
panic("'while' without 'do'");
printf("\tb%s\tL%d\n",operands,np->second_label_number);
}
else
printf("%s\n",ssave);
more: ;
}
if (current_nest_level >= 0)
panic("didn't close all your control structures");
}